#!/usr/bin/env python
# -*- coding: utf-8 -*-

from typing import Any

from cta.config.base_config import BaseConfig
from cta.config.cross_section_config.multi_factor_config import MultiFactorConfig
from cta.interface.action.close_position.abstract_close_position_action import AbstractClosePositionAction
from web.constants.close_position_reason import ClosePositionReason
from web.constants.direction import Direction
from web.constants.k_line_movement_pattern import KLineMovementPattern
from web.domain.responsibility_chain_dto import ResponsibilityChainDto
from web.manager.log_manager import LogManager
from web.models import CommodityFutureInfo
from web.models.commodity_future_date_contract_data import CommodityFutureDateContractData
from web.models.optimize2_account import Optimize2Account
from web.models.optimize2_commodity_future_transaction_record import Optimize2CommodityFutureTransactionRecord
from web.util.commodity_future_code_util import CommodityFutureCodeUtil
from web.util.fee_util import FeeUtil

Logger = LogManager.get_logger(__name__)

class Optimize2FluctuationPatternStopLossClosePositionAction(AbstractClosePositionAction):
    """
    规则策略，震荡形态，止损
    """

    def exec(self, responsibility_chain_dto: ResponsibilityChainDto = None) -> Any:

        # 判断是否有止损操作
        if BaseConfig.Enable_Fluctuation_Stop_Loss is False and BaseConfig.Enable_Trend_Stop_Loss is False:
            Logger.warning("没有止损操作")
            super().next(responsibility_chain_dto)
            return
        else:
            Logger.info("规则策略，震荡形态，止损")

        transaction_date: str = responsibility_chain_dto.transaction_date

        # 查询所有账号
        optimize2_account_list: list[Optimize2Account] = self.optimize2_account_dao.find_all()
        for optimize2_account in optimize2_account_list:
            # 查询对应账号的持仓记录
            optimize2_commodity_future_transaction_record_list: list[Optimize2CommodityFutureTransactionRecord] = self.optimize2_commodity_future_transaction_record_dao.find_by_account_name_and_not_close_position(optimize2_account.account_name)
            if optimize2_commodity_future_transaction_record_list is not None and len(optimize2_commodity_future_transaction_record_list) > 0:
                for optimize2_commodity_future_transaction_record in optimize2_commodity_future_transaction_record_list:

                    # 查询期货记录
                    filter_dict = {'code': optimize2_commodity_future_transaction_record.code, 'transaction_date': transaction_date}
                    commodity_future_date_contract_data: CommodityFutureDateContractData = self.commodity_future_date_contract_data_dao.find_one(filter_dict, dict(), list())
                    if commodity_future_date_contract_data is None:
                        Logger.warning("期货在日期[%s]没有交易记录，跳过这个期货", optimize2_commodity_future_transaction_record.code, transaction_date)
                        continue

                    # 查询commodity_future_info记录（大小写不敏感的精确匹配查询）
                    filter_dict = {'code__iexact': CommodityFutureCodeUtil.code_to_contract_code(optimize2_commodity_future_transaction_record.code)}
                    commodity_future_info: CommodityFutureInfo = self.commodity_future_info_dao.find_one(filter_dict, dict(), list())

                    # 计算现在的盈亏
                    actual_profit_and_loss: float = None
                    if optimize2_commodity_future_transaction_record.direction == Direction.Up:
                        actual_profit_and_loss = FeeUtil.calculate_actual_profit_and_loss(optimize2_commodity_future_transaction_record.direction,
                                                                                          optimize2_commodity_future_transaction_record.buy_price,
                                                                                          commodity_future_date_contract_data.close_price,
                                                                                          commodity_future_info.transaction_multiplier,
                                                                                          optimize2_commodity_future_transaction_record.buy_lot)
                    if optimize2_commodity_future_transaction_record.direction == Direction.Down:
                        actual_profit_and_loss = FeeUtil.calculate_actual_profit_and_loss(optimize2_commodity_future_transaction_record.direction,
                                                                                          optimize2_commodity_future_transaction_record.sell_price,
                                                                                          commodity_future_date_contract_data.close_price,
                                                                                          commodity_future_info.transaction_multiplier,
                                                                                          optimize2_commodity_future_transaction_record.sell_lot)
                    # 计算开仓时的保证金
                    open_position_cost: float = None
                    if optimize2_commodity_future_transaction_record.direction == Direction.Up:
                        open_position_cost = FeeUtil.calculate_open_commodity_future_cost(optimize2_commodity_future_transaction_record.buy_price, commodity_future_info, optimize2_commodity_future_transaction_record.buy_lot)
                    if optimize2_commodity_future_transaction_record.direction == Direction.Down:
                        open_position_cost = FeeUtil.calculate_open_commodity_future_cost(optimize2_commodity_future_transaction_record.sell_price, commodity_future_info, optimize2_commodity_future_transaction_record.sell_lot)

                    stop_loss_rate: float = None
                    # 震荡形态
                    if BaseConfig.Enable_Fluctuation_Stop_Loss is True and optimize2_commodity_future_transaction_record.k_line_movement_pattern == KLineMovementPattern.Fluctuation:
                        stop_loss_rate = BaseConfig.Fluctuation_Stop_Loss_Rate
                    # 趋势形态
                    if BaseConfig.Enable_Trend_Stop_Loss is True and optimize2_commodity_future_transaction_record.k_line_movement_pattern == KLineMovementPattern.Trend:
                        stop_loss_rate = BaseConfig.Trend_Stop_Loss_Rate

                    # 如果实际损失已经超过设置的值，则止损
                    if stop_loss_rate is not None and actual_profit_and_loss < 0 and abs(actual_profit_and_loss) > open_position_cost * stop_loss_rate:
                        self.optimize2_commodity_future_transaction_record_dao.update_when_close_position(optimize2_commodity_future_transaction_record.direction,
                                                                                                       transaction_date, commodity_future_date_contract_data.close_price,
                                                                                                       commodity_future_info,
                            optimize2_commodity_future_transaction_record.buy_lot if optimize2_commodity_future_transaction_record.direction == Direction.Up else optimize2_commodity_future_transaction_record.sell_lot,
                                                                                                       ClosePositionReason.Fluctuation_Pattern_Stop_Loss_Close_Position, optimize2_commodity_future_transaction_record.id_)
            else:
                Logger.warning("账号[%s]没有持仓期货", optimize2_account.account_name)

        super().next(responsibility_chain_dto)